#ifndef LOCATION_HPP
#define LOCATION_HPP

#include <cmath>
#include "Location.h"

namespace my
{
const int TDIRECTIONS = 4;
const char CDIRECTIONS[4] = {'N', 'E', 'S', 'W'};
const int DIRECTIONS[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };      //{N, E, S, W}
}

struct location
{
    int row, col;

    location()
      : row(-1)
      , col(-1)
    {
    };

    operator bool () const
    {
        return row!=-1 && col!=-1;
    }
    
    location(int r, int c)
      : row(r)
      , col(c)
    {
    };

    explicit  location(Location loc)
    {
        row = loc.row;
        col = loc.col;
    };

    bool operator < (const location& loc) const
    {
        if ( row == loc.row ) return col < loc.col;
        return row < loc.row;
    };

    bool operator == (const location& loc) const
    {
        return row == loc.row && col == loc.col;
    };

    static double distance(const location &loc1, const location &loc2, const location &area)
    {
      int d1 = std::abs(loc1.row-loc2.row),
          d2 = std::abs(loc1.col-loc2.col),
          dr = std::min(d1, area.row-d1),
          dc = std::min(d2, area.col-d2);
      return std::sqrt(dr*dr + dc*dc);
    };

    
    //returns the new location from moving in a given direction with the edges wrapped
    static location move(const location &loc, int direction, const location &area)
    {
      return location( (loc.row + my::DIRECTIONS[direction][0] + area.row) % area.row,
                       (loc.col + my::DIRECTIONS[direction][1] + area.col) % area.col 
                     );
    };


    static int direction( location from, location to, location area )
    {
      if ( from == to)
        return -1;
      // TODO: проверить верность расчета
      if ( std::abs( to.row - from.row ) > area.row  )
        to.row += to.row < from.row ? area.row : -area.row;

      if ( std::abs( to.col - from.col) > area.col  )
        to.col += to.col < from.col ? area.col : -area.col;

      // TODO: а здесь особенно проверить 
      if  ( to.row - from.row >  to.col - from.col )
        return to.row > from.row ? 0 : 2;
      else if ( to.col - from.col <  to.col - from.col )
        return to.col > from.col ? 1 : 3;
      return -1;
    }

    static int reverse(int direction)
    {
      switch(direction)
      {
        case 0 : return 2;
        case 1 : return 3;
        case 2 : return 0;
        case 3 : return 1;
      }
      return -1;
    }

    /*
        return Location( (loc.row + DIRECTIONS[direction][0] + rows) % rows,
                     (loc.col + DIRECTIONS[direction][1] + cols) % cols );
    */


};



struct item
  : location
{
  int value;

  
  item()
    : location()
    , value(-1)
  {}

  item(int r, int c, int p = -1)
    : location(r, c)
    , value(p)
  {}

  explicit item(location loc, int p = -1)
    : location(loc)
    , value(p)
  {}

};

struct weight_less
{
  bool operator () ( const item& i1, const item& i2) const
  {
    return i1.value < i2.value;
  }
};

#endif //LOCATION_HPP
